
import java.io.IOException;
import java.util.Random;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Javier
 */
public class Game {

    //images
    Image imgPlayer;
    Image imgPlayerExplosion;
    Image imgEnemy;
    Image imgEnemyExplosion;
    Image imgBullet;
    Image imgGameOver;
    Image imgButtons;
    Image imgCounter;
    Image imgPowerUps;


    //player
    private final int NUM_IMG_WIDTH_PLAYER = 4;
    private final int NUM_IMG_WIDTH_PLAYER_EXPLOSION=9;
    private int playerSprite=0;
    private long playerTime;
    private int playerCounter;

    private final static int MAX_PLAYER_LIVES = 5;
    private int playerState=PLAYER_NORMAL;
    private int playerLives=3;
    private long score=0;
    private final static int PLAYER_NORMAL = 0;
    private final static int PLAYER_DEATH = 1;
    private final static int PLAYER_HIT = 2;

    private final int TIME_PLAYER_EXPLOSION = 150;

    private Float playerAngle;
    private final Float vPlayerAngle = new Float(7);
    private Float yPlayer;
    private Float xPlayer;
    private Float scaleX;
    private Float scaleY;
    private Float vxPlayer;
    private Float vyPlayer;
    private int vPlayer=4;
    
    private int wPlayer = 0;
    private int hPlayer = 0;

    private int wPlayerExplosion = 0;
    private int hPlayerExplosion = 0;

    //enemies
    private final int TIME_ENEMY = 600;
    private final int TIME_ENEMY_HIT = 300;
    private final int NUM_IMG_WIDTH_ENEMIES = 11;
    private final int NUM_IMG_HEIGHT_ENEMIES = 2;
    private final int NUM_IMG_WIDTH_ENEMY_EXPLOSION = 5;
    private final int NUM_IMG_HEIGHT_ENEMY_EXPLOSION = 5;


    private final int NUM_ENEMY_TYPES=4;
    private final int GREEN_ENEMY=0;
    private final int RED_ENEMY=1;
    private final int YELLOW_ENEMY=2;
    private final int BLUE_ENEMY=3;
    //private final static int BLACK_ENEMY=4;
    //private final static int PURPLE_ENEMY=7;
    private int enemyCounter[] = new int[NUM_ENEMY_TYPES];

    private final int VEL_BLUE_ENEMY = (1<<10)+512;

    private final int INTERVAL_GREEN_ENEMY = 1400;
    private final int INTERVAL_RED_ENEMY = 1600;
    private final int INTERVAL_BLACK_ENEMY = 1400;

    private final int MAX_ENEMIES = 10;
    private final int MAX_ENEMIES_PER_TYPE = 3;
    private final int NUM_PROPERTIES = 7;

    private final int ENEMY_ENABLE = 0;
    private final int ENEMY_X = 1;
    private final int ENEMY_Y = 2;
    private final int ENEMY_LIVES = 3;
    private final int ENEMY_STATE = 4;
    private final int ENEMY_SPRITE = 5;
    private final int ENEMY_TYPE = 6;

    private final int ENEMY_STATE_NORMAL = 0;
    private final int ENEMY_STATE_DEATH = 1;
    private final int ENEMY_STATE_HIT = 2;

    private int numEnemiesEnabled;
    private final int MIN_NUM_ENEMIES = 2;
    private final int MAX_NUM_ENEMIES = 5;

    private int enemies[] = new int[MAX_ENEMIES * NUM_PROPERTIES];
    private long timeEnemies[] = new long[MAX_ENEMIES];
    private long timeShoot[] = new long[MAX_ENEMIES];

    private int wEnemy;
    private int hEnemy;

    private int wEnemyExplosion;
    private int hEnemyExplosion;

    private final int MIN_RESPAWN = 5000;
    private final int INTERVAL_RESPAWN = 2000;
    private long timeRespawn = 0;
    private int  timeRandom = 0;


    //bullets
    private final int VEL_BULLET = 2;

    private final int MAX_BULLET = 30;
    private final int NUM_PROP_BULLET = 5;

    private final int BULLET_ENABLE = 0;
    private final int BULLET_X = 1;
    private final int BULLET_Y = 2;
    private final int BULLET_VX = 3;
    private final int BULLET_VY = 4;

    private int bullets[] =  new int[MAX_BULLET * NUM_PROP_BULLET];

    private int wBullet;
    private int hBullet;

    //GUI
    private final long INTERVAL_COUNTER= 200;
    private final int NUM_IMG_WIDTH_COUNTER = 3;

    private final int hGUI = 20;
    private int PlayAgainButtonSprite=5;
    private int ReturnToMenuButtonSprite=7;
    private final char[] sScoreText = (new String("Score: ")).toCharArray();

    private int selectedButton=0;

    private int wGameOver;
    private int hGameOver;

    private int wButtons;
    private int hButtons;

    private int wCounter;
    private int hCounter;

    //powerups
    private final int NUM_POWERUP_TYPES=2;
    private final int POWERUP_LIFE=1;
    private final int POWERUP_INVULNERABILITY=2;
    //private int playerPowerUps;

    private int xPowerUp;
    private int yPowerUp;
    private int PowerUpSprite;
    
    private final int NUM_IMG_WIDTH_POWERUPS = 4;

    private int wPowerUps;
    private int hPowerUps;
    
    private int powerUpType;

    private final int MIN_TIME_POWERUP_RESPAWN = 12000;
    private final int INTERVAL_POWERUP_RESPAWN = 6000;
    private final int INTERVAL_POWERUP_DESTRUCTION = 10000;
    private long timePowerUp = 0;
    private int  timePowerUpRandom = 0;
    private long timePowerUpAnimation = 0;


    //misc
    public final static int SURVIVAL_MODE=1;
    private int gameMode;
    Random r = new Random();
    private int turnsToStart=0;


    public Game(int gameMode){
        //initialize the player position and direction
        xPlayer = new Float(MyCanvas.wCanvas>>1);
        yPlayer = new Float(MyCanvas.hCanvas>>1);

        playerAngle= new Float(30);
        playerTime= MyCanvas.cycleStartTime;

        scaleX= Float.cos(Float.toRadians(playerAngle));
        scaleY= Float.sin(Float.toRadians(playerAngle)).Neg();

        LoadImages();

        this.gameMode = gameMode;
        if(gameMode==SURVIVAL_MODE){
            //initialize the powerup respawn variables
            timePowerUp = MyCanvas.cycleStartTime;
            timePowerUpRandom = MIN_TIME_POWERUP_RESPAWN + Math.abs(r.nextInt(INTERVAL_POWERUP_RESPAWN));

            //add the initial enemies and store the actual cycle time for respawning of enemies
            timeRespawn = MyCanvas.cycleStartTime;
            timeRandom = MIN_RESPAWN + Math.abs(r.nextInt(INTERVAL_RESPAWN));
            for(int i=0; i<MIN_NUM_ENEMIES; i++){
                addEnemy(Math.abs(r.nextInt(NUM_ENEMY_TYPES)));
            }
        }
        
        //for(int j=0; j<6 ;j++){
           // for(int i=0; i<2; i++){
             //   addEnemy(NUM_ENEMY_TYPES);
            //}
        //}
    }

    public void addBullet(int enemy, int x, int y){
        //find an empty slot for the new bullet
        for (int i = 0; i < bullets.length; i+=NUM_PROP_BULLET) {
            if(bullets[i+BULLET_ENABLE] == 0){
                createBullet(i, enemy, x, y);
                return;
            }
        }
    }

    public void addEnemy(int type){
        //find an empty slot for the new enemy
        for (int i = 0; i < enemies.length; i+=NUM_PROPERTIES) {
            if(enemies[i+ENEMY_ENABLE] == 0){
                createEnemy(i, type);
                return;
            }
        }
    }

    private void createBullet(int i, int enemy, int x, int y) {
        //store the velocity and initial position of the bullet
        bullets[i +  BULLET_ENABLE] = 1;
        bullets[i +  BULLET_X] =  ((enemies[enemy + ENEMY_X] + (wEnemy>>1) - (wBullet>>1))<<10) + x*(wEnemy>>1);
        bullets[i +  BULLET_Y] =  ((enemies[enemy + ENEMY_Y] + (hEnemy>>1) - (hBullet>>1))<<10) + y*(hEnemy>>1);
        bullets[i +  BULLET_VX]= x;
        bullets[i +  BULLET_VY]= y;
    }

    private void createEnemy(int i, int type) {

        
        //limit the number of enemies of a same type on screen

        while(enemyCounter[type]>MAX_ENEMIES_PER_TYPE){
            type=Math.abs(r.nextInt(NUM_ENEMY_TYPES));
        }

        //calculate the random initial position and type of the enemy
        boolean done=false;
        enemies[i + ENEMY_X] = Math.abs(r.nextInt(MyCanvas.wCanvas-wEnemy-10))+5;
        enemies[i + ENEMY_Y] = Math.abs(r.nextInt(MyCanvas.hCanvas-hEnemy-10-hGUI))+5+hGUI;

        //avoid setting the enemies too close of each other
        if(numEnemiesEnabled>0){
            do{
                for (int j = 0; j < enemies.length; j+=NUM_PROPERTIES) {
                        if(enemies[j+ENEMY_ENABLE] == 1){
                            //calculate the enemy's center and radius
                            int pxEnemy1 = enemies[i + ENEMY_X] + (wEnemy>>1);
                            int pyEnemy1 = enemies[i + ENEMY_Y] + (hEnemy>>1);

                            int pxEnemy2 = enemies[j + ENEMY_X] + (wEnemy>>1);
                            int pyEnemy2 = enemies[j + ENEMY_Y] + (hEnemy>>1);

                            int rEnemy = hEnemy >> 1;

                            int d = ((pxEnemy1 - pxEnemy2)*(pxEnemy1 - pxEnemy2)) +
                                ((pyEnemy1 - pyEnemy2)*(pyEnemy1 - pyEnemy2));

                            int rad = (rEnemy*rEnemy)+(rEnemy*rEnemy);

                            //if there's collision
                            if(d<rad){
                                //try with a different position
                                enemies[i + ENEMY_X] = Math.abs(r.nextInt(MyCanvas.wCanvas-wEnemy-10))+5;
                                enemies[i + ENEMY_Y] = Math.abs(r.nextInt(MyCanvas.hCanvas-hEnemy-10-hGUI))+5+hGUI;
                                break;
                            }
                            else{
                                done=true;
                            }
                        }
                }
            }while(!done);
        }
        enemies[i + ENEMY_SPRITE] = type<<1;
        enemies[i + ENEMY_TYPE] = type;
        enemies[i + ENEMY_STATE] = ENEMY_STATE_NORMAL;
        //update the counter of enemies
        enemyCounter[type]++;
        numEnemiesEnabled++;

        //set the number of lives of the enemy depending on the type
        switch(type){
            case YELLOW_ENEMY:
                enemies[i + ENEMY_LIVES] = 3;
                break;
            default:
                enemies[i + ENEMY_LIVES] = 1;
        }
        enemies[i + ENEMY_ENABLE] = 1;
    }

    private void createPowerUp(){
        //set the type of powerup
        powerUpType = Math.abs(r.nextInt(NUM_POWERUP_TYPES))+1;

        //set sprite of that type of powerup
        PowerUpSprite=(powerUpType-1)<<1;

        //convert the type of powerup to a bit flag format
        //if(powerUpType == 1){
        //    powerUpType = 1;
        //}
        //else{
        //    powerUpType = 2<<(powerUpType-1);
        //}
        
        xPowerUp = Math.abs(r.nextInt(MyCanvas.wCanvas-wPowerUps-10))+5;
        yPowerUp = Math.abs(r.nextInt(MyCanvas.hCanvas-hPowerUps-10-hGUI))+5+hGUI;      
        boolean done=false;
        
        //calculate the player's center and radius
        int pxPlayer=(int) xPlayer.toLong()+(wPlayer>>1);
        int pyPlayer=(int) yPlayer.toLong()+(hPlayer>>1);
        int rPlayer = hPlayer >> 1;
        
        //avoid setting the powerup too close to something
        do{
            //calculate the powerup's center and radius
            int pxPowerUp = xPowerUp + (wPowerUps>>1);
            int pyPowerUp = yPowerUp + (hPowerUps>>1);
            int rPowerUp = hPowerUps >> 1;

            //collision enemy-powerup
            for (int i = 0; i < enemies.length; i+=NUM_PROPERTIES) {
                if(enemies[i+ENEMY_ENABLE] == 1){
                    //calculate the enemy's center and radius
                    int pxEnemy = enemies[i + ENEMY_X] + (wEnemy>>1);
                    int pyEnemy = enemies[i + ENEMY_Y] + (hEnemy>>1);

                    int rEnemy = hEnemy >> 1;

                    int d = ((pxEnemy - pxPowerUp)*(pxEnemy - pxPowerUp)) +
                        ((pyEnemy - pyPowerUp)*(pyEnemy - pyPowerUp));

                    int rad = (rPowerUp*rPowerUp)+(rEnemy*rEnemy);

                    //if there's collision
                    if(d<rad){
                        //try with a different position
                        xPowerUp = Math.abs(r.nextInt(MyCanvas.wCanvas-wPowerUps-10))+5;
                        yPowerUp = Math.abs(r.nextInt(MyCanvas.hCanvas-hPowerUps-10-hGUI))+5+hGUI;
                        break;
                    }
                }
            }

           //collision player-powerup
           int d1 = ((pxPlayer - pxPowerUp)*(pxPlayer - pxPowerUp)) +
                        ((pyPlayer - pyPowerUp)*(pyPlayer - pyPowerUp));

           int rad1 = (rPowerUp*rPowerUp)+(rPlayer*rPlayer);

           //if there's collision
           if(d1<rad1){
               //try with a different position
               xPowerUp = Math.abs(r.nextInt(MyCanvas.wCanvas-wPowerUps-10))+5;
               yPowerUp = Math.abs(r.nextInt(MyCanvas.hCanvas-hPowerUps-10-hGUI))+5+hGUI;
               break;
           }
           else{
               done = true;
           }
        }while(!done);
    }

    public void LoadImages() {
        try {
            //load all the images in memory
            imgPlayer = Image.createImage("/player.png");
            imgPlayerExplosion = Image.createImage("/playerExplosion.png");
            imgEnemy = Image.createImage("/enemies.png");
            imgEnemyExplosion = Image.createImage("/enemiesExplosion.png");
            imgBullet = Image.createImage("/bullet.png");
            imgGameOver = Image.createImage("/gameover.png");
            imgButtons = Image.createImage("/buttons.png");
            imgCounter = Image.createImage("/counter.png");
            imgPowerUps = Image.createImage("/powerups.png");

            //get the size of every image
            wPlayer = imgPlayer.getWidth()/NUM_IMG_WIDTH_PLAYER;
            hPlayer = imgPlayer.getHeight();

            wPlayerExplosion = imgPlayerExplosion.getWidth()/NUM_IMG_WIDTH_PLAYER_EXPLOSION;
            hPlayerExplosion = imgPlayerExplosion.getHeight();


            wEnemy = imgEnemy.getWidth()/NUM_IMG_WIDTH_ENEMIES;
            hEnemy = imgEnemy.getHeight()/NUM_IMG_HEIGHT_ENEMIES;

            wEnemyExplosion = imgEnemyExplosion.getWidth()/NUM_IMG_WIDTH_ENEMY_EXPLOSION;
            hEnemyExplosion = imgEnemyExplosion.getHeight()/NUM_IMG_HEIGHT_ENEMY_EXPLOSION;

            wBullet = imgBullet.getWidth();
            hBullet = imgBullet.getHeight();

            wButtons = imgButtons.getWidth();
            hButtons = imgButtons.getHeight()/MainMenu.NUM_IMG_HEIGHT_BUTTONS;

            wGameOver = imgGameOver.getWidth();
            hGameOver = imgGameOver.getHeight();

            wCounter = imgCounter.getWidth()/NUM_IMG_WIDTH_COUNTER;
            hCounter = imgCounter.getHeight();

            wPowerUps = imgPowerUps.getWidth()/NUM_IMG_WIDTH_POWERUPS;
            hPowerUps = imgPowerUps.getHeight();

        } catch (IOException ex)
        { }
    }


    public void paint(Graphics g) {
        //draw the background
        g.drawImage(MyCanvas.imgBg, 0, 0, Graphics.LEFT|Graphics.TOP);

        paintPowerUp(g);
        paintEnemy(g);
        paintBullet(g);
        paintPlayer(g);
        paintGUI(g);
        //if you lose all the lives the gameover menu is drawn
        if(MyCanvas.isFinished == true){
            paintGameOver(g);
        }
        //when you start a new game it draws a counter (3,2,1)
        else if(turnsToStart<3){
            paintCounter(g);
        }
    }

    private void paintBullet(Graphics g) {
        //draw all the bullets in their positions (no animation)
        for (int i = 0; i < bullets.length; i+=NUM_PROP_BULLET) {
           if(bullets[i+BULLET_ENABLE] == 1){
              g.drawImage(imgBullet, bullets[i+BULLET_X]>>10, bullets[i+BULLET_Y]>>10, Graphics.LEFT|Graphics.TOP);
           }
        }
    }

    private void paintCounter(Graphics g){
        //draw the counter (it depends of the variable turnsToStart)
        g.setClip((MyCanvas.wCanvas>>1)-(wCounter>>1), (MyCanvas.hCanvas>>1)-(hCounter>>1), wCounter, hCounter);
        g.drawImage(imgCounter, (MyCanvas.wCanvas>>1)-(wCounter>>1)- wCounter*(turnsToStart%NUM_IMG_WIDTH_COUNTER), (MyCanvas.hCanvas>>1)-(hCounter>>1), Graphics.LEFT|Graphics.TOP);
        g.setClip(0, 0, MyCanvas.wCanvas, MyCanvas.hCanvas);
    }

    private void paintGameOver(Graphics g){
        //draw the "Game Over" text
        int yGameOver = (MyCanvas.hCanvas>>1)-60;
        g.drawImage(imgGameOver, 26, yGameOver, Graphics.LEFT|Graphics.TOP);

        //draw the button for playing again
        g.setClip(26, yGameOver+hGameOver+20, wButtons, hButtons);
        g.drawImage(imgButtons, 26, yGameOver+hGameOver+20-hButtons*(PlayAgainButtonSprite), Graphics.LEFT|Graphics.TOP);

        //draw the button for returning to the main menu
        g.setClip(26,  yGameOver+hGameOver+hButtons+40, wButtons, hButtons);
        g.drawImage(imgButtons, 26, yGameOver+hGameOver+hButtons+40-hButtons*(ReturnToMenuButtonSprite), Graphics.LEFT|Graphics.TOP);
        g.setClip(0, 0, MyCanvas.wCanvas,MyCanvas.hCanvas);
    }

    private void paintGUI(Graphics g) {
        //set the bar at the top of the screen
        g.setColor(0x8fa6a4);
        g.fillRect(0, 0, MyCanvas.wCanvas, hGUI);

        //draw the player 1 time for each remaining life
        for(int i= 0; i<playerLives; i++){
            int x=3+(wPlayer+10)*i;
            int y=(hGUI>>1) - (hPlayer>>1);
            g.setClip(x, y, wPlayer, hPlayer);
            g.drawImage(imgPlayer, x, y, Graphics.LEFT|Graphics.TOP);

        }

        //draw the score
        g.setClip(0, 0, MyCanvas.wCanvas,MyCanvas.hCanvas);
        char[] sScore= Long.toString(score).toCharArray();       

        g.setColor(0x000000);
        g.drawChars(sScoreText, 0, sScoreText.length, (MyCanvas.wCanvas>>1)+10, 0, Graphics.LEFT|Graphics.TOP);
        g.drawChars(sScore, 0, sScore.length, (MyCanvas.wCanvas>>1)+50, 0, Graphics.LEFT|Graphics.TOP);

    }


    private void paintEnemy(Graphics g) {

        for (int i = 0; i < enemies.length; i+=NUM_PROPERTIES) {
           if(enemies[i+ENEMY_ENABLE] == 1){
               //draw an explosion if the enemy dies
               if(enemies[i+ENEMY_STATE] == ENEMY_STATE_DEATH){
                    g.setClip( enemies[i+ENEMY_X] + (wEnemy>>1) -(wEnemyExplosion>>1) ,
                            enemies[i+ENEMY_Y] + (hEnemy>>1) -(hEnemyExplosion>>1), wEnemyExplosion,hEnemyExplosion);
                    g.drawImage(imgEnemyExplosion,  enemies[i+ENEMY_X] + (wEnemy>>1) -(wEnemyExplosion>>1) - (enemies[i+ENEMY_SPRITE]%NUM_IMG_WIDTH_ENEMY_EXPLOSION)* wEnemyExplosion,
                             enemies[i+ENEMY_Y] + (hEnemy>>1) -(hEnemyExplosion>>1) - (enemies[i+ENEMY_SPRITE]/NUM_IMG_WIDTH_ENEMY_EXPLOSION)* hEnemyExplosion, Graphics.LEFT|Graphics.TOP);
               }
               //draw a shield effect if it's hit
               else if(enemies[i+ENEMY_STATE] == ENEMY_STATE_HIT){
                   g.setClip( enemies[i+ENEMY_X],enemies[i+ENEMY_Y],wEnemy,hEnemy);
                   g.drawImage(imgEnemy, enemies[i+ENEMY_X]-wEnemy*((enemies[i + ENEMY_TYPE]<<1)%NUM_IMG_WIDTH_ENEMIES), enemies[i+ENEMY_Y]-hEnemy*((enemies[i + ENEMY_TYPE]<<1)/NUM_IMG_WIDTH_ENEMIES), Graphics.LEFT|Graphics.TOP);
                   g.drawImage(imgEnemy, enemies[i+ENEMY_X]-wEnemy*(enemies[i+ENEMY_SPRITE]%NUM_IMG_WIDTH_ENEMIES), enemies[i+ENEMY_Y]-hEnemy*(enemies[i+ENEMY_SPRITE]/NUM_IMG_WIDTH_ENEMIES), Graphics.LEFT|Graphics.TOP);
               }
               //draw only the enemy if it's normal
               else if(enemies[i+ENEMY_STATE] == ENEMY_STATE_NORMAL){
                    g.setClip( enemies[i+ENEMY_X],enemies[i+ENEMY_Y],wEnemy,hEnemy);
                   g.drawImage(imgEnemy, enemies[i+ENEMY_X]-wEnemy*(enemies[i+ENEMY_SPRITE]%NUM_IMG_WIDTH_ENEMIES), enemies[i+ENEMY_Y]-hEnemy*(enemies[i+ENEMY_SPRITE]/NUM_IMG_WIDTH_ENEMIES), Graphics.LEFT|Graphics.TOP);
               }

           }
        }
        g.setClip(0,0,MyCanvas.wCanvas,MyCanvas.hCanvas);
    }

    private void paintPlayer(Graphics g) {
        //draw the trail of the player of a different color depending the direction of turn
        if(playerState!=PLAYER_DEATH){
            if(MyCanvas.isClockwise==false){
                //if it's counterclockwise draw it red
                g.setColor(0xff0000);
                playerSprite%=2;
            }
            else{
                //if it's clockwise draw it blue
                g.setColor(0x0000ff);
                playerSprite=2+(playerSprite%2);
            }
        }
        //convert to int the position and velocity vector
        int x = ((int) xPlayer.toLong());
        int y = ((int) yPlayer.toLong());
        int sx = ((int) scaleX.Mul(20).toLong());
        int sy = ((int) scaleY.Mul(20).toLong());

        //when the player dies draw an explosion
        if(playerState==PLAYER_DEATH){
            g.setClip(x + (wPlayer>>1) -(wPlayerExplosion>>1) , y + (hPlayer>>1) -(hPlayerExplosion>>1), wPlayerExplosion, hPlayerExplosion);
            g.drawImage(imgPlayerExplosion, x + (wPlayer>>1) -(wPlayerExplosion>>1) - (playerSprite%NUM_IMG_WIDTH_PLAYER_EXPLOSION)* wPlayerExplosion, y + (hPlayer>>1) -(hPlayerExplosion>>1), Graphics.LEFT|Graphics.TOP);
        }
        //draw the player if it's not the case
        else{
            g.drawLine(x + (wPlayer>>1), y + (hPlayer>>1), x + (wPlayer>>1)-sx, y + (hPlayer>>1) - sy);
            g.setClip(x, y, wPlayer, hPlayer);
            g.drawImage(imgPlayer, x-wPlayer*(playerSprite%NUM_IMG_WIDTH_PLAYER), y, Graphics.LEFT|Graphics.TOP);
        }
        g.setClip(0, 0, MyCanvas.wCanvas,MyCanvas.hCanvas);
    }

    private void paintPowerUp(Graphics g){
        if(powerUpType != 0){
            g.setClip(xPowerUp, yPowerUp, wPowerUps, hPowerUps);
            g.drawImage(imgPowerUps, xPowerUp-wPowerUps*(PowerUpSprite%NUM_IMG_WIDTH_POWERUPS), yPowerUp, Graphics.LEFT|Graphics.TOP);
            g.setClip(0, 0, MyCanvas.wCanvas,MyCanvas.hCanvas);
        }
    }

    private void processBullet() {
        for (int i = 0; i < bullets.length; i+=NUM_PROP_BULLET) {
            if(bullets[i + BULLET_ENABLE] == 1 ){
                //calculate the new bullet position
                bullets[i+ BULLET_X]+=bullets[i+ BULLET_VX]*VEL_BULLET;
                bullets[i+ BULLET_Y]+=bullets[i+ BULLET_VY]*VEL_BULLET;

                //if the bullet goes out of the screen delete it
                if((bullets[i + BULLET_Y] + (hBullet<<10) < 0) || (bullets[i + BULLET_Y]>>10 >= MyCanvas.hCanvas) || (bullets[i + BULLET_X]>>10 >= MyCanvas.wCanvas) || (bullets[i + BULLET_X] + (wBullet<<10) < 0)){
                    bullets[i + BULLET_ENABLE] = 0;
                }
            }
        }
    }

    private void processCollision() {
       //calculate the player's center and radius
       int pxPlayer=(int) xPlayer.toLong()+(wPlayer>>1);
       int pyPlayer=(int) yPlayer.toLong()+(hPlayer>>1);
       int rPlayer = hPlayer >> 1;
       //collision bullet-player
        if((playerState == PLAYER_NORMAL) || (playerState == PLAYER_HIT)){
            for(int j = 0; j< bullets.length; j+= NUM_PROP_BULLET){
                if(bullets[j+BULLET_ENABLE] == 1){
                    //calculate the bullet's center and radiues
                    int rBullet = hBullet >> 1;

                    int pxBullet = (bullets[j + BULLET_X]>>10) + (wBullet>>1);
                    int pyBullet = (bullets[j + BULLET_Y]>>10) + (rBullet);
                    

                    int d = ((pxBullet - pxPlayer)*(pxBullet - pxPlayer)) +
                        ((pyBullet - pyPlayer)*(pyBullet - pyPlayer));

                    int rad = (rBullet*rBullet)+(rPlayer*rPlayer);
                    //if there's collision
                    if(d<rad){ 
                        //delete the bullet
                        bullets[j + BULLET_ENABLE] = 0;
                        //if the player can be hit
                        if(playerState == PLAYER_NORMAL){
                            //the player loses 1 life and gets invulnerable for a while
                            playerLives--;
                            playerState=PLAYER_HIT;
                            playerSprite++;
                            playerTime = MyCanvas.cycleStartTime;
                            playerCounter=3;
                            //if the player has no lives he dies
                            if(playerLives <= 0){
                                playerState = PLAYER_DEATH;
                                playerSprite=0;
                            }
                        }
                    }
                }
            }

            //collision enemy-player
            for (int i = 0; i < enemies.length; i+=NUM_PROPERTIES) {
                if((enemies[i+ENEMY_ENABLE] == 1)&&(enemies[i+ENEMY_STATE] == ENEMY_STATE_NORMAL)){
                    //calculate the enemy's center and radiues
                    int pxEnemy = enemies[i + ENEMY_X] + (wEnemy>>1);
                    int pyEnemy = enemies[i + ENEMY_Y] + (hEnemy>>1);

                    int rEnemy = hEnemy >> 1;

                    int d = ((pxPlayer - pxEnemy)*(pxPlayer - pxEnemy)) +
                        ((pyPlayer - pyEnemy)*(pyPlayer - pyEnemy));

                    int rad = (rPlayer*rPlayer)+(rEnemy*rEnemy);

                    //if there's collision
                    if(d<rad){
                        //the enemy loses a live
                        enemies[i + ENEMY_LIVES]--;
                        //when the enemy has 0 lives it dies and you get points
                        if(enemies[i + ENEMY_LIVES] <= 0){
                            enemies[i + ENEMY_STATE] = ENEMY_STATE_DEATH;
                            switch(enemies[i + ENEMY_TYPE]){
                                case GREEN_ENEMY:
                                    score+=400;
                                    break;
                                case RED_ENEMY:
                                    score+=700;
                                    break;
                                case YELLOW_ENEMY:
                                    score+=1500;
                                    break;
                                case BLUE_ENEMY:
                                    score+=1000;
                                    break;
                               // case BLACK_ENEMY:
                               //     score+=1800;
                            }
                            //change the sprite to the explosion
                            enemies[i + ENEMY_SPRITE] = (enemies[i + ENEMY_SPRITE]>>1)*3;
                            timeEnemies[i/NUM_PROPERTIES] = MyCanvas.cycleStartTime;
                        }
                        //when the enemy has 1 or more lives change the sprite to the shield
                        else if(enemies[i + ENEMY_STATE]!=ENEMY_STATE_HIT){
                            enemies[i + ENEMY_SPRITE] = 16;
                            timeEnemies[i/NUM_PROPERTIES] = MyCanvas.cycleStartTime;
                            enemies[i + ENEMY_STATE] = ENEMY_STATE_HIT;
                        }
                    }
                }
            }

            //collision player-powerup
            if(powerUpType!=0){
                //calculate the powerup's center and radius
                int pxPowerUp = xPowerUp + (wPowerUps>>1);
                int pyPowerUp = yPowerUp + (hPowerUps>>1);
                int rPowerUp = hPowerUps >> 1;

                int d1 = ((pxPlayer - pxPowerUp)*(pxPlayer - pxPowerUp)) +
                            ((pyPlayer - pyPowerUp)*(pyPlayer - pyPowerUp));

                int rad1 = (rPowerUp*rPowerUp)+(rPlayer*rPlayer);

                //if there's collision
                if(d1<rad1){
                    switch(powerUpType){
                        case POWERUP_LIFE:
                            //if it's life type and player has not reached the maximum number of lifes
                            // his lifes are increased by 1
                            if(playerLives<=MAX_PLAYER_LIVES){
                                playerLives++;
                            }
                        break;
                            //if it's invulnerability type the player changes to hit mode for a while (can't be hitted)
                        case POWERUP_INVULNERABILITY:
                            playerState=PLAYER_HIT;
                            playerSprite++;
                            playerTime = MyCanvas.cycleStartTime;
                            playerCounter=9;
                    }
                    //delete the powerup
                    powerUpType = 0;
                }
            }
        }
    }

    private void processGameOver(){
        //if enough time has passed since the last mouse click
        if(MyCanvas.cycleStartTime - playerTime > MainMenu.INTERVAL_CLICK){
            playerTime = MyCanvas.cycleStartTime;
            //update the selected button
            if(MyCanvas.moveUp==true){
                if(selectedButton>0){
                    selectedButton--;
                }
            }
            if(MyCanvas.moveDown==true){
                if(selectedButton<1){
                    selectedButton++;
                }
            }

            //if the player has pressed the fire button
            if(MyCanvas.fire==true){
                //if the selected option was to play again the game is resetted
                if(selectedButton==0){
                    reset();
                    MyCanvas.isFinished=false;
                }
                //if it was to return to the menu it is loaded
                else{
                    MyCanvas.classOption=MyCanvas.MENU_OPTION;
                    MyCanvas.isFinished=false;
                }
            }
            
            //change the sprites if the selected button has changed
            if(selectedButton==0){
                PlayAgainButtonSprite=6;
                ReturnToMenuButtonSprite=7;
            }
            else{
                PlayAgainButtonSprite=5;
                ReturnToMenuButtonSprite=8;
            }
        }
    }

    private void processEnemies() {
        for (int i = 0; i < enemies.length; i+=NUM_PROPERTIES) {
            if(enemies[i + ENEMY_ENABLE] == 1 ){
                if(enemies[i + ENEMY_STATE] == ENEMY_STATE_NORMAL || enemies[i + ENEMY_STATE] == ENEMY_STATE_HIT){
                      if((MyCanvas.cycleStartTime - timeEnemies[i/NUM_PROPERTIES] > TIME_ENEMY_HIT) && (enemies[i + ENEMY_STATE] == ENEMY_STATE_HIT)){
                          //if the last sprite of the shield animation (hit state) has been drawn return to normal state
                         if(enemies[i + ENEMY_SPRITE]==19){
                            enemies[i + ENEMY_SPRITE] = enemies[i + ENEMY_TYPE]*2;
                            enemies[i + ENEMY_STATE] = ENEMY_STATE_NORMAL;
                          }
                          // if not continue with the animation
                          else{
                            enemies[i + ENEMY_SPRITE]++;
                          }
                      }

                      //animate the enemy when it's in normal state
                     if(MyCanvas.cycleStartTime - timeEnemies[i/NUM_PROPERTIES] > TIME_ENEMY){
                          timeEnemies[i/NUM_PROPERTIES ] = MyCanvas.cycleStartTime;
                          if(enemies[i + ENEMY_STATE] == ENEMY_STATE_NORMAL){
                             //when it reaches the last sprite return to the first one
                             if(enemies[i + ENEMY_SPRITE]%2!=0){
                                  enemies[i + ENEMY_SPRITE] -= enemies[i + ENEMY_SPRITE]%2;
                             }
                             else{
                                 enemies[i + ENEMY_SPRITE]++;
                             }
                          }
                     }

                     //if it's in normal state
                     if(enemies[i + ENEMY_STATE] == ENEMY_STATE_NORMAL){
                         Float px;
                         Float py;
                         switch(enemies[i + ENEMY_TYPE]){
                             case YELLOW_ENEMY:
                             case GREEN_ENEMY:
                                 //if it's a green or yellow enemy type shoot towards the player at intervals
                                if(MyCanvas.cycleStartTime - timeShoot[i/NUM_PROPERTIES] > INTERVAL_GREEN_ENEMY){                                    
                                    px = xPlayer.Sub(new Float(enemies[i + ENEMY_X]));
                                    py = yPlayer.Sub(new Float(enemies[i + ENEMY_Y]));
                                    Float modulo = Float.sqrt(px.Mul(px).Add(py.Mul(py)));
                                    //calculate the unitary vector from the enemy to the player
                                    int ipx=((int) px.toLong())<<10;
                                    int ipy=((int) py.toLong())<<10;
                                    int imodulo= ((int) modulo.toLong());
                                    //only shoot if the player is not too close
                                    if(imodulo>25){
                                        timeShoot[i/NUM_PROPERTIES] = MyCanvas.cycleStartTime;
                                        addBullet(i, ipx/imodulo, ipy/imodulo);
                                    }
                                }
                                break;

                             case RED_ENEMY:
                                 //if it's a blue enemy type shoot to the four directions(north,west,south,east)
                                 if(MyCanvas.cycleStartTime - timeShoot[i/NUM_PROPERTIES] > INTERVAL_RED_ENEMY){
                                     timeShoot[i/NUM_PROPERTIES] = MyCanvas.cycleStartTime;
                                     addBullet(i, -1<<10, 0);
                                     addBullet(i, 1<<10, 0);
                                     addBullet(i, 0, 1<<10);
                                     addBullet(i, 0, -1<<10);
                                 }
                                 break;

                             case BLUE_ENEMY:
                                 //if it's a blue enemy type shoot towards the player at intervals and move towards him
                                 px = xPlayer.Sub(new Float(enemies[i + ENEMY_X]));
                                 py = yPlayer.Sub(new Float(enemies[i + ENEMY_Y]));
                                 Float modulo = Float.sqrt(px.Mul(px).Add(py.Mul(py)));
                                 int ipx=((int) px.toLong())<<10;
                                 int ipy=((int) py.toLong())<<10;
                                 int imodulo= ((int) modulo.toLong());
                                 //calculate the unitary vector from the enemy to the player
                                 int xVector = ipx/imodulo;
                                 int yVector = ipy/imodulo;
                                 enemies[i + ENEMY_X] += ((xVector*VEL_BLUE_ENEMY)>>20);
                                 enemies[i + ENEMY_Y] += ((yVector*VEL_BLUE_ENEMY)>>20);
                                 //only shoot if the player is not too close
                                 if((MyCanvas.cycleStartTime - timeShoot[i/NUM_PROPERTIES] > INTERVAL_GREEN_ENEMY)&&(imodulo>25)){
                                    timeShoot[i/NUM_PROPERTIES] = MyCanvas.cycleStartTime;
                                    addBullet(i, xVector, yVector);
                                }
                                break;
                             /*case BLACK_ENEMY:
                                 if(MyCanvas.cycleStartTime - timeShoot[i/NUM_PROPERTIES] > INTERVAL_BLACK_ENEMY){
                                     timeShoot[i/NUM_PROPERTIES] = MyCanvas.cycleStartTime;
                                     px = xPlayer.Sub(new Float(enemies[i + ENEMY_X]));
                                     py = yPlayer.Sub(new Float(enemies[i + ENEMY_Y]));
                                     Float angle = Float.atan2(py,px);
                                     //addBullet(i, ((int)Float.cos(new Float(angle.m_Val)).toFixedPoint()), ((int) Float.sin(a).toFixedPoint()));
                                 }*/

                         }
                     }
                }
                else{
                    //if the enemy is dead set the explosion animation
                    if(MyCanvas.cycleStartTime - timeEnemies[i/NUM_PROPERTIES] > TIME_PLAYER_EXPLOSION){
                        timeEnemies[i/NUM_PROPERTIES ] = MyCanvas.cycleStartTime;
                        enemies[i + ENEMY_SPRITE] ++;
                        //when the explosion animation ends delete the enemy and update the counter
                        if(enemies[i + ENEMY_SPRITE]%3 == 0){
                            enemyCounter[enemies[i + ENEMY_TYPE]]--;
                            enemies[i + ENEMY_ENABLE] = 0;
                            numEnemiesEnabled--;
                        }
                    }
                }
            }
        }
    }

    private void processPlayer() {
        switch(playerState){
           case PLAYER_HIT:
               if(MyCanvas.cycleStartTime - playerTime > TIME_ENEMY_HIT){
                   //if you have been hit set the proper animation
                   playerTime = MyCanvas.cycleStartTime;
                   if(playerSprite%2!=0){
                       playerSprite--;
                       playerCounter--;
                       if(playerCounter==0){
                           playerState=PLAYER_NORMAL;
                       }
                   }
                   else{
                        playerSprite++;
                   }
               }
           case PLAYER_NORMAL:
           {
              //if the fire button has been pressed turn the player
             if(MyCanvas.fire == true){
                 if(MyCanvas.isClockwise){
                     playerAngle = playerAngle.Sub(vPlayerAngle);
                 }
                 else{
                     playerAngle = playerAngle.Add(vPlayerAngle);
                 }

                 //avoid overflow using an equivalent angle if it's too high or too low
                 if(playerAngle.Great(Float.G360)){
                     playerAngle = playerAngle.Sub(Float.G360);
                 }
                 else if(playerAngle.Less(Float.ZERO)){
                     playerAngle = playerAngle.Add(Float.G360);
                 }
             }
             //calculate the new player position
             scaleX= Float.cos(Float.toRadians(playerAngle));
             scaleY= Float.sin(Float.toRadians(playerAngle)).Neg();
             vxPlayer = scaleX.Mul(vPlayer);
             vyPlayer = scaleY.Mul(vPlayer);
             xPlayer=xPlayer.Add(vxPlayer);
             yPlayer=yPlayer.Add(vyPlayer);

             //if the player reaches an screen boundary it bounces against it
             if(xPlayer.Less(0)){
                xPlayer.change(0);
                playerAngle = playerAngle.Add(Float.G270).Neg().Sub(Float.G270);
             }
             else if(!(xPlayer.Less(MyCanvas.wCanvas - wPlayer+1))){
                 xPlayer.change(MyCanvas.wCanvas - wPlayer);
                 playerAngle = playerAngle.Add(Float.G90).Neg().Sub(Float.G90);
             }

             if(yPlayer.Less(hGUI)){
                yPlayer.change(hGUI);
                playerAngle = playerAngle.Neg();
             }
             else if(!(yPlayer.Less(MyCanvas.hCanvas - hPlayer+1))){
                yPlayer.change(MyCanvas.hCanvas - hPlayer);
                playerAngle = playerAngle.Add(Float.G180).Neg().Sub(Float.G180);
             }
             break;
           }
           case PLAYER_DEATH:
           {
               if(MyCanvas.cycleStartTime - playerTime > TIME_PLAYER_EXPLOSION){
                   playerTime=MyCanvas.cycleStartTime;
                   //if the player is dead and the explosion animation ends stop the game and show the game over menu
                   if(playerSprite==(NUM_IMG_WIDTH_PLAYER_EXPLOSION-1)){
                       MyCanvas.isFinished=true;             
                   }
                   //if not continue with the explosion animation
                   else{
                       playerSprite++;
                   }
               }
               break;
           }
        }
    }

    private void processPowerUps(){
        if(MyCanvas.cycleStartTime - timePowerUp > timePowerUpRandom){
            //when the respawn interval is reached add a new powerup and update the respawn variables
            timePowerUp = MyCanvas.cycleStartTime;
            timePowerUpRandom = MIN_TIME_POWERUP_RESPAWN + Math.abs(r.nextInt(INTERVAL_POWERUP_RESPAWN));
            timePowerUpAnimation = MyCanvas.cycleStartTime;

            createPowerUp();
        }

        //when the destruction interval is reached destroy the powerup
        if((powerUpType != 0) && (MyCanvas.cycleStartTime - timePowerUp > INTERVAL_POWERUP_DESTRUCTION)){
            powerUpType = 0;
        }

        //animate the powerup
        if((powerUpType != 0) && (MyCanvas.cycleStartTime - timePowerUpAnimation > TIME_ENEMY_HIT)){
            timePowerUpAnimation = MyCanvas.cycleStartTime;
            if(PowerUpSprite%2!=0){
                PowerUpSprite--;
            }
            else{
                PowerUpSprite++;
            }
        }
    }

    public void processTick() {
        //if the game is not finished and the counter has ended
        if((MyCanvas.isFinished == false) && (turnsToStart >= 3)){
            //do the proper calculations of the game mode
            if(gameMode == SURVIVAL_MODE){
                survivalMode();
            }

            processPlayer();
            processEnemies();
            processBullet();
            processPowerUps();

            processCollision();
        }
        //if the counter has not ended
        if((turnsToStart < 3) && (MyCanvas.cycleStartTime - playerTime > INTERVAL_COUNTER)){
            playerTime=MyCanvas.cycleStartTime;
            turnsToStart++;
            //when the counter ends
            if(turnsToStart==3){
                //if the actual mode is survival 
                if(gameMode==SURVIVAL_MODE){
                    //set the enemy respawn variables
                    timeRespawn = MyCanvas.cycleStartTime;
                    timeRandom = MIN_RESPAWN + Math.abs(r.nextInt(INTERVAL_RESPAWN));
                    //set the powerup respawn variables
                    timePowerUp = MyCanvas.cycleStartTime;
                    timePowerUpRandom = MIN_TIME_POWERUP_RESPAWN + Math.abs(r.nextInt(INTERVAL_POWERUP_RESPAWN));
                }
            }
        }
        //if the game is finished draw the gameOver menu
        if(MyCanvas.isFinished == true) {
             processGameOver();
        }
    }


    public void reset(){
        //delete all the bullets
        for (int i = 0; i < bullets.length; i+=NUM_PROP_BULLET) {
            bullets[i + BULLET_ENABLE] = 0;
        }
        //delete all the enemies
        for (int i = 0; i < enemies.length; i+=NUM_PROPERTIES) {
            enemies[i + ENEMY_ENABLE] = 0;
        }

        //reset all the enemy type counters
       for(int i=0; i<NUM_ENEMY_TYPES; i++){
            enemyCounter[i]=0;
        }

        //reset all the stats, the sprite, position, velocity ,the enemy counter
        //and the counter used to start the game
        playerLives=3;
        playerSprite=0;
        score=0;
        playerState=PLAYER_NORMAL;
        playerAngle= new Float(30);
        turnsToStart=0;
        //playerPowerUps=0;

        numEnemiesEnabled=0;

        xPlayer = new Float(MyCanvas.wCanvas>>1);
        yPlayer = new Float(MyCanvas.hCanvas>>1);

        scaleX= Float.cos(Float.toRadians(playerAngle));
        scaleY= Float.sin(Float.toRadians(playerAngle)).Neg();

        //if the actual mode is survival set the minimum number of enemies
        if(gameMode==SURVIVAL_MODE){
            for(int i=0; i<MIN_NUM_ENEMIES; i++){
                addEnemy(Math.abs(r.nextInt(NUM_ENEMY_TYPES)));
            }
        }
        playerTime=MyCanvas.cycleStartTime;
    }


    public void survivalMode(){
        if(MyCanvas.cycleStartTime - timeRespawn > timeRandom){
            //when the respawn interval is reached add a new enemy and update the respawn variables
            timeRespawn = MyCanvas.cycleStartTime;
            timeRandom = MIN_RESPAWN + Math.abs(r.nextInt(INTERVAL_RESPAWN));
            if(numEnemiesEnabled<MAX_NUM_ENEMIES){
                addEnemy(Math.abs(r.nextInt(NUM_ENEMY_TYPES)));
            }
        }

        //keep always a minimum of enemies on screen
        while(numEnemiesEnabled<MIN_NUM_ENEMIES){
            addEnemy(Math.abs(r.nextInt(NUM_ENEMY_TYPES)));
        }
    }


}
